﻿using CrawlerFramework.ConfigEntity;
using CrawlerFramework.Models;
using CrawlerFramework.Repository;
using MediaBot.Entities;
using MediaBot.Library;
using RakutenProxy.ConfigEntity;
using RakutenProxy.Model.Rakuten;
using RakutenProxy.Repository;
using System;
using System.Collections;
using System.Xml;

namespace RakutenProxy.PageProcessor
{
    internal class RakutenHomePageProcessor : CrawlerFramework.PageProcessor.PageProcessor
    {
        public RakutenHomePageProcessor(LinkConfig linkConfig, Link link)
            : base(linkConfig, link)
        {
        }

        public override CrawlerFramework.Models.CrawlStatus Execute()
        {
            Logger.Info("Start with url: " + Link.Url);

            if (!ShouldExecute())
                return CrawlStatus.Paused;

            var categoryRepo = new BaseRakutenRepository<Model.Rakuten.Category>();
            var linkRepo = new LinkRepository();
            try
            {
                Link.BeginExecution();

                var categoryConverter = DataConverter.RakutenDataConverterFactory.GetDataConverter(typeof(Category));

                var entityConfigPath = LinkConfig.BuildEntityConfigPath();
                var xmlSerializer = new XmlSerializer<RakutenHomeConfig>();
                var homeConfig = xmlSerializer.Deserialize(entityConfigPath);

                var namespaces = Utils.GetDefaultNamespaces();

                var xmlWebPage = new XmlWebPage(new Uri(Link.Url), namespaces);
                xmlWebPage.Download();

                var nsManager = xmlWebPage.XmlNamespaceManager;
                
                var categoryNodes = xmlWebPage.SelectNodes(homeConfig.CategoryNode.Context);
                foreach (XmlNode categoryNode in categoryNodes)
                {
                    var categoryName = homeConfig.CategoryName.GetString(categoryNode, nsManager);
                    var categoryUrl = homeConfig.CategoryUrl.GetString(categoryNode, nsManager);

                    var category = new Category { CategoryName = categoryName, CategoryUrl = categoryUrl };
                    categoryRepo.Add(category);
                    categoryRepo.Save();

                    ConvertData(category.CategoryId, categoryConverter);

                    var subGenreNodes = categoryNode.SelectNodes(homeConfig.SubCategory.SubCategoryNode.Context, nsManager);

                    foreach (XmlNode subCategoryNode in subGenreNodes)
                    {
                        var subCategoryName = homeConfig.SubCategory.SubCategoryName.GetString(subCategoryNode, nsManager);
                        var subCategoryUrl = homeConfig.SubCategory.SubCategoryUrl.GetString(subCategoryNode, nsManager);

                        var subCategory = new Category { CategoryName = subCategoryName, CategoryUrl = subCategoryUrl, ParentCategoryId = category.CategoryId };
                        categoryRepo.Add(subCategory);
                        categoryRepo.Save();

                        ConvertData(subCategory.CategoryId, categoryConverter);

                        var link = new Link { Url = subCategoryUrl, RelatedEntityId = subCategory.CategoryId, RelatedEntityName = typeof(Category).Name };
                        linkRepo.Add(link);
                    }

                    linkRepo.Save();
                }
            }
            catch (Exception e)
            {
                var method = System.Reflection.MethodBase.GetCurrentMethod();
                var exceptionOnMethod = string.Format("{0}.{1}", method.ReflectedType, method.Name);

                var errorMessage = Utils.BuildErrorMessage(method, LinkConfig.Guid, Link.LinkId);
                Logger.Error(errorMessage, e);

                Link.EndExecution(CrawlStatus.CompletedWithError);
                return CrawlStatus.CompletedWithError;
            }
            finally
            {
                categoryRepo.Dispose();
                linkRepo.Dispose();
                // When done
                if (DoneEvent != null) DoneEvent.Set();

                Logger.Info("Finish link: " + Link.Url);
            }

            Link.EndExecution(CrawlStatus.Completed);
            return CrawlStatus.Completed;
        }
    }
}